/*

settings:

	selector - (li)
	time - (300)
	maxTime - (time * 2)
	
	onClick(prevPos,pos)
	onAnimationStart(prevPos,pos,duration);
	onAnimationEnd(prevPos,pos,duration);

functions:

	jump(pos) - Jump to position
	animate(pos) - Animate to position

*/


(function($) {
	var pi2 = Math.PI * 2, 
		methods = {
			init: function(options) {
				var settings = $.extend( {
					selector: 'li',
					time: 300
				},options);
				settings.maxTime = settings.maxTime || settings.time * 5;
				return this.each(function() {
					var menu = $(this),
						items = menu.find(settings.selector),
						count = items.length,
						context = menu.data('wheelmenu'),
						rx = settings.rx || menu.width() / 2,
						ry = settings.ry || menu.height() / 2,
						positions = [],
						i, ppos,
						draw = function(i,ang) {
							var item = $(this);
							item.css({
								left: rx - rx * Math.sin(ang) - item.width() / 2,
								top: ry + ry * Math.cos(ang) - item.height() / 2
							});
						};
						for (var i = 0; i < count; i++)
							positions[i] = settings.positions[i] * Math.PI / 180;
					if (!context) {
						context = {
							jump: function(pos) {
								if (pos === ppos) return;
								for (var i = 0; i < count; i++) {
									var ang = positions[(count + i - pos) % count];
									$(items[i]).prop('wheelmenu_ang',ang);
									draw.call(items[i],i,ang);
								}
								ppos = pos;
							},
							animate: function(pos) {
								if (pos === ppos) return;
								var cw = 0, 
									deltav = [],
									i, duration, onAnimationEnd;
								for (i = 0; i < count; i++) {
									if ((deltav[i] = positions[(count + i - pos) % count] - 
										positions[(count + i - ppos) % count]) < 0) cw++;
								}
								cw = cw >= count / 2;
								for (i = 0; i < count; i++) {
									var d = deltav[i];
									if (cw) deltav[i] = d >= 0 ? ('-=' + (pi2 - d)) : ('-=' + -d);
									else deltav[i] = d >= 0 ? ('+=' + d) : ('+=' + (pi2 + d));
								}
								duration = settings.time + (settings.maxTime - 
										settings.time) / settings.duration;
								i = 0;
								if (settings.onAnimationStart) settings.onAnimationStart(ppos,pos,duration);
								items.each(function() {
									var i2 = i, item = this;
									$(item).animate({
										'wheelmenu_ang': deltav[i]
									},{
										step: function(ang) {
											draw.call(item,i2,ang);
										},
										duration: duration
									});
									i++;
								});
								ppos = pos;
							}
						};
						if (settings.onClick) {
							items.click(function() {
								var pos = $(this).index();
								if (pos === ppos) return;
								settings.onClick(ppos,pos);
							});
						}
						context.jump(0);
						menu.data('wheelmenu',context);
					}
				});
			},
			jump: function(pos) {
				return this.each(function() {
					var menu = $(this),
						context = menu.data('wheelmenu');
					if (context) context.jump(pos || 0);
				})
			},
			animate: function(pos) {
				return this.each(function() {
					var menu = $(this),
						context = menu.data('wheelmenu');
					if (context) context.animate(pos || 0);
				})
			}
		};
	$.fn.wheelmenu = function(method) {		
		if (methods[method]) {
			return methods[method].apply(this,Array.prototype.slice.call(arguments,1));
		} else if (typeof method === 'object' || ! method) {			
			return methods.init.apply(this,arguments);
		} else {
			$.error('Method ' +	method + ' does not exist on jQuery.wheelmenu');
		}
	};
})(jQuery);